iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0

洛基走進茶室還在想著昨天大師提到「重新思考資料組織方式」。

洛基坐下後說道,「昨天我學會了 Query 的基本操作,能夠查詢火星基地在特定時間範圍的活動。但我在想,如果我需要支援更多種查詢方式怎麼辦?」

諾斯克大師微笑:「很好的問題!這就是今天要解決的挑戰。」他在白板上寫下一個現實場景:

星際活動系統的新需求:
原有:查詢火星基地在特定時間的活動 ✓ (昨天已解決)
新增:
1. 按主題查詢活動 (例如:所有 Foundation 主題的活動)
2. 按星球查詢活動 (例如:火星的所有活動,不限時間)

「讓我們從簡單的開始,」大師說,「用你昨天學到的技能,先試試能否解決這兩個新需求。」

回顧:昨天的設計方案

洛基回想起 Day05 學到的方案:

{
  "PK": "LOCATION#MARS",
  "SK": "DATE#SY210-03-15#EVENT#001",
  "name": "火星防禦研討會",
  "topic": "Foundation",
  "speaker": "Asimov",
  "capacity": 500
}

「這個設計能夠很好地支援『查詢火星基地特定時間範圍的活動』,」洛基分析,「但如果我要查詢所有 Foundation 主題的活動呢?」

嘗試用現有設計解決新需求

需求1:按主題查詢活動

洛基嘗試查詢所有 Foundation 主題的活動:

# 嘗試按主題查詢
aws dynamodb query \
  --table-name IntergalacticEvents \
  --key-condition-expression "topic = :topic" \
  --expression-attribute-values '{":topic": {"S": "Foundation"}}' \
  --endpoint-url http://localhost:8000

結果報錯:Query condition missed key schema element

洛基困惑:「為什麼不行?topic 明明就在資料裡啊!」

「因為 topic 不是 Key,」大師解釋,「Query 只能基於 Key (PK 和 SK) 來查詢。其他欄位只能用 Scan + Filter 的方式。」

洛基嘗試 Scan:

# 用 Scan 查詢主題
aws dynamodb scan \
  --table-name IntergalacticEvents \
  --filter-expression "topic = :topic" \
  --expression-attribute-values '{":topic": {"S": "Foundation"}}' \
  --endpoint-url http://localhost:8000

「能找到結果,但是...」洛基看著 ConsumedCapacity,「這個成本好高!它掃描了整個表格!」

需求2:按星球查詢活動(不限時間)

# 查詢火星的所有活動
aws dynamodb query \
  --table-name IntergalacticEvents \
  --key-condition-expression "PK = :pk" \
  --expression-attribute-values '{":pk": {"S": "LOCATION#MARS"}}' \
  --endpoint-url http://localhost:8000

「這個倒是可以!」洛基鬆了一口氣,「因為 PK 就是 LOCATION#MARS。」

設計問題的核心發現

洛基整理他的發現:

當前設計的查詢能力:
✓ 按星球查詢活動 → Query (高效)
✓ 按星球+時間範圍查詢 → Query (高效)
❌ 按主題查詢活動 → 只能 Scan (低效)
❌ 按講者查詢活動 → 只能 Scan (低效)
❌ 按日期查詢活動 → 只能 Scan (低效)

「我明白了!」洛基恍然大悟,「在 DynamoDB 中,只有設計成 Key 的欄位才能高效查詢。如果我想要高效地按主題查詢,就必須讓主題也變成某個 Key。」

大師點頭:「正確的理解!那你覺得應該怎麼解決?」

多視角設計的思維轉換

洛基思考了一會兒:「如果我想要高效地按主題查詢...我需要一個以主題為 PK 的『視角』?」

「很好的想法!讓我示範給你看。」大師在白板上畫出新的設計:

設計思維轉換:一個實體,多個視角

同一個活動,可以從不同角度儲存:

視角1:按星球查詢
{
  "PK": "PLANET#MARS",
  "SK": "EVENT#001",
  "name": "火星防禦研討會",
  "topic": "Foundation",
  "date": "SY210-03-15"
}

視角2:按主題查詢
{
  "PK": "TOPIC#Foundation",
  "SK": "EVENT#001",
  "name": "火星防禦研討會",
  "planet": "MARS",
  "date": "SY210-03-15"
}

洛基驚訝:「同一個活動...儲存兩次?在傳統資料庫中這是重複資料啊!」

「這就是 NoSQL 思維的重要轉換,」大師說,「我們用『空間換時間』。重複儲存是為了獲得查詢效能。」

實際測試多視角設計

讓我們建立測試資料:

# 視角1:按星球查詢的資料
aws dynamodb put-item \
  --table-name IntergalacticEvents \
  --item '{
    "PK": {"S": "PLANET#MARS"},
    "SK": {"S": "EVENT#001"},
    "name": {"S": "火星防禦研討會"},
    "topic": {"S": "Foundation"},
    "date": {"S": "SY210-03-15"},
    "speaker": {"S": "Asimov"}
  }' \
  --endpoint-url http://localhost:8000

# 視角2:按主題查詢的資料
aws dynamodb put-item \
  --table-name IntergalacticEvents \
  --item '{
    "PK": {"S": "TOPIC#Foundation"},
    "SK": {"S": "EVENT#001"},
    "name": {"S": "火星防禦研討會"},
    "planet": {"S": "MARS"},
    "date": {"S": "SY210-03-15"},
    "speaker": {"S": "Asimov"}
  }' \
  --endpoint-url http://localhost:8000

現在測試查詢:

# 按星球查詢 (使用視角1)
aws dynamodb query \
  --table-name IntergalacticEvents \
  --key-condition-expression "PK = :pk" \
  --expression-attribute-values '{":pk": {"S": "PLANET#MARS"}}' \
  --endpoint-url http://localhost:8000

# 按主題查詢 (使用視角2)
aws dynamodb query \
  --table-name IntergalacticEvents \
  --key-condition-expression "PK = :pk" \
  --expression-attribute-values '{":pk": {"S": "TOPIC#Foundation"}}' \
  --endpoint-url http://localhost:8000

洛基執行後驚喜地說:「兩個查詢都能高效執行!而且都是 Query 操作,不是 Scan!」

多視角設計的核心理解

Hippo 跳出來補充:「讓我用圖表幫你理解這個概念!」

傳統關聯式思維:
Events Table → 一個活動只存一次
查詢不同維度 → 需要複雜的索引或 JOIN

DynamoDB 多視角思維:
同一個活動 → 按照不同查詢需求,建立不同的「視角」
每個視角 → 都是為特定查詢優化的資料組織方式

視角1: PLANET# → 支援按星球查詢
視角2: TOPIC# → 支援按主題查詢
視角3: DATE# → 支援按日期查詢 (如果需要的話)

洛基點頭:「所以每個視角就像是為特定查詢需求量身訂做的『快速通道』!」

「完美的比喻!」大師讚許,「每個視角都讓某種查詢變得極其高效。」

實用的設計原則

大師在白板上寫下重要原則:

多視角設計的基本原則:

1. 識別查詢需求
   - 用戶會如何使用這個系統?
   - 哪些查詢是最常見的?

2. 為重要查詢建立視角
   - 每個常用查詢都應該有對應的視角
   - 用不同的 PK 支援不同的查詢維度

3. 接受資料重複
   - 同一個實體在不同視角中重複儲存
   - 這是為了查詢效能的合理代價

4. 保持資料一致性
   - 更新時需要同時更新所有相關視角
   - 這是多視角設計的維護考量

洛基認真記錄:「所以設計 DynamoDB 表格時,我應該先問:『用戶會如何查詢這些資料?』」

「正確!」大師說,「這就是 NoSQL 設計思維的核心轉換。」

大師接著補充:「今天你學會了多視角設計的基本概念。明天,我們會看看當查詢需求繼續增加時會遇到什麼新的挑戰。」

Hippo 的課外教學

多視角設計的實用技巧

「讓我分享一些實用的設計技巧!」Hippo 說。

// 視角設計的命名規範
const viewNamingPatterns = {
  byPlanet: "PLANET#{planetName}",     // 按星球查詢
  byTopic: "TOPIC#{topicName}",        // 按主題查詢
  byDate: "DATE#{date}",               // 按日期查詢
  bySpeaker: "SPEAKER#{speakerName}",  // 按講者查詢
  byStatus: "STATUS#{status}"          // 按狀態查詢
};

// 實體重複的策略
const entityDuplication = {
  fullCopy: "完整複製所有欄位到每個視角",
  partialCopy: "每個視角只包含該查詢需要的欄位",
  referencePattern: "視角只包含 ID,詳細資料另外查詢"
};

常見的多視角設計模式

# 模式1:基本多視角 (2-3個查詢維度)
# 適用:簡單的查詢需求

# 模式2:分層視角 (時間 + 分類)
PK: "TOPIC#Foundation"
SK: "DATE#SY210-03-15#EVENT#001"
# 既能按主題查詢,又能按主題+時間範圍查詢

# 模式3:複合視角 (多個維度組合)
PK: "PLANET#MARS#TOPIC#Foundation"
SK: "EVENT#001"
# 支援特定星球+特定主題的組合查詢

設計決策的考量點

何時使用多視角設計?
✓ 查詢模式明確且固定
✓ 查詢效能要求高
✓ 可以接受一些維護複雜度

上一篇
Day 5:Query 與 Get 的差異
下一篇
Day 7:複雜度的自然累積
系列文
DynamoDB銀河傳說首部曲-打造宇宙都打不倒的高效服務21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言